/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       cache_base.cpp

	$Header: /game/cache_base.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "cache_base.h"

#include <assert.h>

// ------------------------------------------------------------
// unnamed namespace
// ------------------------------------------------------------
	
namespace
{
	const unsigned int  k_min_cache_mem_size	= 2*1024*1000;			// 2 megs
	const unsigned int  k_cache_divide_factor   = 8;
	const unsigned int	k_max_cache_mem_size	= k_min_cache_mem_size;

	unsigned int		g_free_list_cache_size	= 0;
	bool				g_list_destroyed		= false;

	inline t_cache_base_list& get_free_list()
	{
		static t_cache_base_list g_free_list;

		return g_free_list;
	}

} // unnamed namespace

t_cache_base_list::~t_cache_base_list()
{
	iterator index = begin();

	while (index != end())
	{
    (*index)->m_position = t_cache_base_list::iterator();
		(*index)->release_memory();
		index++;
	}
	g_list_destroyed = true;
}


// ------------------------------------------------------------
// base class for caching objects.  
// ------------------------------------------------------------
t_cache_base::t_cache_base()
{
	m_reference_count	= 0;
	m_destroyed			= false;
	m_cahce_size		= 0;
}

// ------------------------------------------------------------
// base class for caching objects.  
// ------------------------------------------------------------
t_cache_base::~t_cache_base()
{
	remove_from_free_list();
	m_destroyed = true;
}

// ------------------------------------------------------------
// base class for caching objects.  
// ------------------------------------------------------------
void t_cache_base::check_memory()
{
	if (g_free_list_cache_size < k_max_cache_mem_size) 
		return;
	
	//remove if we can remove enough elements from the cache list to reach
	//our cache size limits
	
	t_cache_base_list& list = get_free_list();
	
	list.lock();
	
	while (!list.empty() && g_free_list_cache_size > k_max_cache_mem_size)
	{
		t_cache_base* cache = list.back();
		
		list.pop_back();
		
		cache->m_position = t_cache_base_list::iterator();
		
		g_free_list_cache_size -= cache->get_size();
		
		cache->release_memory();
	}
	
	list.unlock();
}

// ------------------------------------------------------------
// base class for caching objects.  
// ------------------------------------------------------------
void t_cache_base::add_to_free_list()
{
	assert( m_position._Mynode() == NULL );
	if (g_list_destroyed)
		return;

	t_cache_base_list& list = get_free_list();

	list.lock();
	list.push_front( this );
	m_position = list.begin();
	m_cahce_size = get_size();
	g_free_list_cache_size += m_cahce_size;
	list.unlock();
}

// ------------------------------------------------------------
// base class for caching objects.  
// ------------------------------------------------------------
void t_cache_base::remove_from_free_list()
{
	if (g_list_destroyed)
		return;

	t_cache_base_list& list = get_free_list();

	list.lock();
	if ( m_position._Mynode() != NULL )
	{
		list.erase( m_position );
		m_position = t_cache_base_list::iterator();
		g_free_list_cache_size -= m_cahce_size;
	}
	list.unlock();
}

